﻿using Hx.ADSyncPlatform.ActiveDirectory.Access;
using Hx.ADSyncPlatform.ActiveDirectory.Extension;
using Hx.ADSyncPlatform.ActiveDirectory.Model;
using Hx.ADSyncPlatform.ActiveDirectory.Service.Base;
using Hx.ADSyncPlatform.Entity.Entities;
using Hx.ADSyncPlatform.Infrastructure.Page;
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Linq;
using System.Text;

namespace Hx.ADSyncPlatform.ActiveDirectory.Service
{
    /// <summary>
    /// 组
    /// </summary>
    public class GroupService : BaseService
    {

        private ADConnection ADCInfo;
        public GroupService(ADConnection _adcInfo)
        {
            this.ADCInfo = _adcInfo;
        }

        //hack：方法名不统一
        /// <summary>
        /// 组
        /// </summary>
        /// <param name="sAMAccountName">组名称</param>
        /// <returns>组信息</returns>
        public Group Single(string sAMAccountName)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                var group = new GroupAccess().Single(adc.RootEntry, sAMAccountName);
                var result = group == null ? null : group.Properties?.ConvertTo<Group>();
                return result;
            }
        }
        public Group SingleByDN(string dn)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                var group = new GroupAccess().SingleByDistinguishedName(adc.RootEntry, dn);
                var result = group == null ? null : group.Properties?.ConvertTo<Group>();
                return result;
            }
        }
        ///// <summary>
        ///// 查询组织下的组
        ///// </summary>
        ///// <param name="orgCn">所在组织</param>
        ///// <param name="searchScope">查询层级</param>
        ///// <param name="searchLocation">查询位置</param>
        ///// <returns>组集合</returns>
        //public List<Group> Get(string orgCn, SearchScopeDerivation searchScope)
        //{
        //    using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
        //    {
        //        DirectoryEntry org = null;
        //        var orgDe = new OrganizationAccess().Single(adc.RootEntry, orgCn);
        //        if (orgDe == null)
        //        {
        //            //hack:此处用NullReferenceException这个异常不合适
        //            throw new ActiveDirectoryObjectNotFoundException($"组织【CN:{orgCn}】不存在，查询无法继续。");
        //        }
        //        org = orgDe.GetDirectoryEntry();
        //        var groups = new GroupAccess().Get(org, searchScope.Convert());

        //        List<Group> data = new List<Group>();
        //        if (groups == null || groups.Count == 0)
        //        {
        //            return data;
        //        }

        //        //hack：if 缩进
        //        foreach (SearchResult group in groups)
        //        {
        //            var groupItem = group.Properties?.ConvertTo<Group>();
        //            if (groupItem != null)
        //            {
        //                data.Add(groupItem);
        //            }
        //        }
        //        return data;
        //    }
        //}
        /// <summary>
        /// 查询组织下的组
        /// </summary>
        /// <param name="orgCn">所在组织</param>
        /// <param name="searchScope">查询层级</param>
        /// <param name="searchLocation">查询位置</param>
        /// <returns>组集合</returns>
        public List<Group> Get(string orgDN, string displayName, ConfigItem groupConfig, List<Plat_DataPermission> dataPermissions, List<string> systemOus, string searchScope = "current")
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                SearchResultCollection src = null;
                var orgAccess = new OrganizationAccess();

                DirectoryEntry org = null;
                var orgDe = orgAccess.SingleByDistinguishedName(adc.RootEntry, orgDN);
                if (orgDe == null)
                {
                    throw new ActiveDirectoryObjectNotFoundException($"组织【{orgDN}】不存在，查询无法继续。");
                }
                org = orgDe.GetDirectoryEntry();


                string groupDN = $"OU={groupConfig.name},{orgDN}";
                var groupSr = orgAccess.SingleByDistinguishedName(org, groupDN);
                if (searchScope == "current")
                {
                    src = new GroupAccess().Get(groupSr.GetDirectoryEntry(), SearchScope.OneLevel, displayName);
                }
                else if (searchScope == "global")
                {
                    src = new GroupAccess().Get(adc.RootEntry, SearchScope.Subtree, displayName);
                }
                var searchResults = src.OfType<SearchResult>();
                if (base.filterObjectByDataPermission != null)
                {
                    searchResults = filterObjectByDataPermission(searchResults, dataPermissions, systemOus);
                }
                List<Group> data = new List<Group>();
                if (src == null || src.Count == 0)
                {
                    return data;
                }

                //hack：if 缩进
                foreach (SearchResult group in searchResults)
                {
                    var groupItem = group.Properties?.ConvertTo<Group>();
                    if (groupItem != null)
                    {
                        data.Add(groupItem);
                    }
                }
                return data;
            }
        }

        /// <summary>
        /// 查询组分页
        /// </summary>
        /// <param name="orgCn">组织CN</param>
        /// <param name="displayName">显示名</param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns>人员分页集合</returns>
        public PageResult<Group> PageList(string orgDN, string displayName, ConfigItem groupConfig, List<Plat_DataPermission> dataPermissions, List<string> systemOus, string searchScope = "current", int pageIndex = 1, int pageSize = 10)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                SearchResultCollection src = null;
                var orgAccess = new OrganizationAccess();

                DirectoryEntry org = null;
                var orgDe = orgAccess.SingleByDistinguishedName(adc.RootEntry, orgDN);
                if (orgDe == null)
                {
                    throw new ActiveDirectoryObjectNotFoundException($"组织【{orgDN}】不存在，查询无法继续。");
                }
                org = orgDe.GetDirectoryEntry();


                string groupDN = $"OU={groupConfig.name},{orgDN}";
                var groupSr = orgAccess.SingleByDistinguishedName(org, groupDN);

                if (groupSr == null)
                {
                    Organization organization = new Organization()
                    {
                        CN = groupConfig.cn,
                        Name = groupConfig.name,
                        DisplayName = groupConfig.name,
                        Ou = groupConfig.name

                    };

                    orgAccess.Create(org, organization);
                    groupSr = orgAccess.SingleByDistinguishedName(org, groupDN);
                }
                if (searchScope == "current")
                {
                    src = new GroupAccess().Get(groupSr.GetDirectoryEntry(), SearchScope.OneLevel, displayName);
                }
                else if (searchScope == "global")
                {
                    src = new GroupAccess().Get(adc.RootEntry, SearchScope.Subtree, displayName);
                }

                var searchResults = src.OfType<SearchResult>();

                if (base.filterObjectByDataPermission != null)
                {
                    searchResults = filterObjectByDataPermission(searchResults, dataPermissions, systemOus);
                }
                int total = searchResults.Count();
                int startNum = Math.Max(pageIndex - 1, 0) * pageSize;
                searchResults = searchResults.Skip(startNum).Take(pageSize);

                var groups = searchResults.Select(n =>
                {
                    return n.Properties?.ConvertTo<Group>();

                }).OrderByDescending(n => n.WhenCreated).Skip(startNum).Take(pageSize).ToList();

                PageResult<Group> pageResult = new PageResult<Group>(groups, pageIndex, total);
                return pageResult;



            }
        }


        /// <summary>
        /// 查询组分页
        /// </summary>
        /// <param name="orgCn">组织CN</param>
        /// <param name="displayName">显示名</param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns>人员分页集合</returns>
        public PageResult<Group> PageList(string orgDN, string displayName, SystemConfig systemConfig, List<Plat_DataPermission> dataPermissions, string searchScope = "current", int pageIndex = 1, int pageSize = 10)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                SearchResultCollection src = null;
                var orgAccess = new OrganizationAccess();

                DirectoryEntry org = null;

                if (searchScope == "current")
                {
                    var orgDe = orgAccess.SingleByDistinguishedName(adc.RootEntry, orgDN);
                    if (orgDe == null)
                    {
                        throw new ActiveDirectoryObjectNotFoundException($"组织【{orgDN}】不存在，查询无法继续。");
                    }
                    org = orgDe.GetDirectoryEntry();


                    string groupDN = $"OU={systemConfig.group.name},{orgDN}";
                    var groupSr = orgAccess.SingleByDistinguishedName(org, groupDN);


                    if (systemConfig.excludeOU.Any())
                    {
                        string dn = orgDe.Properties["distinguishedName"][0].ToString();
                        if (systemConfig.excludeOU.Any(n => dn.Contains(n.name)))
                        {
                            groupSr = orgDe;
                        }

                    }
                    else
                    {

                    }
                    if (groupSr == null)
                    {
                        Organization organization = new Organization()
                        {
                            CN = systemConfig.group.cn,
                            Name = systemConfig.group.name,
                            DisplayName = systemConfig.group.name,
                            Ou = systemConfig.group.name

                        };

                        orgAccess.Create(org, organization);
                        groupSr = orgAccess.SingleByDistinguishedName(org, groupDN);
                    }

                    src = new GroupAccess().Get(groupSr.GetDirectoryEntry(), SearchScope.OneLevel, displayName);
                }
                else if (searchScope == "global")
                {
                    src = new GroupAccess().Get(adc.RootEntry, SearchScope.Subtree, displayName);
                }

                var searchResults = src.OfType<SearchResult>();

                if (base.filterObjectByDataPermission != null)
                {
                    searchResults = filterObjectByDataPermission(searchResults, dataPermissions, systemConfig.systemOU.Select(n => n.name).ToList());
                }



                int total = searchResults.Count();
                int startNum = Math.Max(pageIndex - 1, 0) * pageSize;
                searchResults = searchResults.Skip(startNum).Take(pageSize);

                var groups = searchResults.Select(n =>
                {
                    return n.Properties?.ConvertTo<Group>();

                }).OrderByDescending(n => n.WhenCreated).Skip(startNum).Take(pageSize).ToList();

                PageResult<Group> pageResult = new PageResult<Group>(groups, pageIndex, total);
                return pageResult;



            }
        }

        /// <summary>
        /// 查询组下人员列表 分页
        /// </summary>
        /// <param name="samAccountName">samAccountName</param>
        /// <param name="displayName">person显示名</param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns>人员分页集合</returns>
        public PageResult<Person> PersonPageList(string samAccountName, string displayName, int pageIndex = 1, int pageSize = 10)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                SearchResultCollection src = null;
                if (string.IsNullOrEmpty(samAccountName))
                {
                    throw new ActiveDirectoryObjectNotFoundException($"必须指定组CN");
                }
                DirectoryEntry groupDe = null;
                var groupSe = new GroupAccess().Single(adc.RootEntry, samAccountName);
                if (groupSe == null)
                {
                    throw new ActiveDirectoryObjectNotFoundException($"组【{samAccountName}】不存在，无法继续查询！");
                }
                groupDe = groupSe.GetDirectoryEntry();
                List<string> members = groupDe.Properties?.ConvertTo<Group>().Member;
                if (members == null) members = new List<string>();
                if (!string.IsNullOrEmpty(displayName))
                {
                    members = members.Where(n => n.Split(",")[0].Substring(3).Contains(displayName)).ToList();
                }

                List<Person> people = new List<Person>();
                int total = 0;
                if (members != null)
                {
                    total = members.Count;
                    int startNum = Math.Max(pageIndex - 1, 0) * pageSize;
                    members = members.Skip(startNum).Take(pageSize).ToList();
                    people = members.Select(dn =>
                    {
                        var person = new PersonAccess().SingleByDistinguishedName(adc.RootEntry, dn);
                        return person?.Properties?.ConvertTo<Person>();
                    }).ToList();
                }

                PageResult<Person> pageResult = new PageResult<Person>(people, pageIndex, total);
                return pageResult;



            }
        }

        /// <summary>
        /// 自定义查询
        /// </summary>
        /// <param name="filter">LDAP查询语句</param>
        /// <param name="propertiesToLoad">需要返回的属性</param>
        /// <param name="searchScope">查询层级</param>
        /// <param name="pagination">分页信息，NULL时返回所有</param>
        /// <returns>组集合以及分页信息</returns>
        public PageResult<Group> Search(string filter, List<string> propertiesToLoad, SearchScopeDerivation searchScope, int pageIndex = 1, int pageSize = 10)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                var src = new GroupAccess().Search(adc.RootEntry, filter, propertiesToLoad, searchScope.Convert(), pageIndex * pageSize);
                int total = src.Count;
                int startNum = Math.Max(pageIndex - 1, 0) * pageSize;
                var searchResults = src.OfType<SearchResult>().Skip(startNum).Take(pageSize).ToList();

                var computerList = searchResults.Select(n =>
                {
                    return n.Properties?.ConvertTo<Group>();

                }).ToList();

                PageResult<Group> pageResult = new PageResult<Group>(computerList, pageIndex, total);
                return pageResult;
            }
        }

        /// <summary>
        /// 创建
        /// </summary>
        /// <param name="orgCn">组创建的组织下</param>
        /// <param name="group">组信息</param>
        /// <returns>成功True，失败False</returns>
        /// 
        public bool Create(string orgDN,SystemConfig systemConfig, Group group)
        {
            ConfigItem groupConfig = systemConfig.group;
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                var orgAccess = new OrganizationAccess();
                DirectoryEntry org = null;
                var orgDe = orgAccess.SingleByDistinguishedName(adc.RootEntry, orgDN);
           
                if (orgDe == null)
                {
                    //hack:此处用NullReferenceException这个异常不合适
                    throw new ActiveDirectoryObjectNotFoundException($"组织【DN:{orgDN}】不存在，创建请求无法继续。");
                }
                org = orgDe.GetDirectoryEntry();
            
                string groupDN = $"OU={groupConfig.name},{orgDN}";
                var groupSr = orgAccess.SingleByDistinguishedName(orgDe.GetDirectoryEntry(), groupDN);
                if (systemConfig.excludeOU.Any())
                {
                    string dn = orgDe.Properties["distinguishedName"][0].ToString();
                    if (systemConfig.excludeOU.Any(n => dn.Contains(n.name)))
                    {
                        groupSr = orgDe;
                    }

                }
                if (groupSr == null)
                {
                    Organization organization = new Organization()
                    {
                        CN = groupConfig.cn,
                        Name = groupConfig.name,
                        DisplayName = groupConfig.name,
                        Ou = groupConfig.name

                    };

                    orgAccess.Create(org, organization);
                    groupSr = orgAccess.SingleByDistinguishedName(org, groupDN);
                }
                org = groupSr.GetDirectoryEntry();
                var groupAccess = new GroupAccess();
                List<string> members = group.Member;
                group.AssignedAttributes.Remove(nameof(group.Member));


                //获取管理员员DN
                if (!string.IsNullOrWhiteSpace(group.ManagedBy))
                {
                    var person = new PersonService(ADCInfo).Single(group.ManagedBy);
                    if (person != null)
                        group.ManagedBy = person.DistinguishedName;
                }

                var result = groupAccess.Create(org, group);
                if (result && members != null && members.Any())
                {
                    var groupDe = groupAccess.Single(adc.RootEntry, group.SamAccountName);
                    if (groupDe != null)
                    {
                        AddMember(groupDe.GetDirectoryEntry(), members, groupAccess);
                    }
                }
                return result;
            }
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="group">组新信息</param>
        /// <returns>成功True，失败False</returns>
        public bool Update(Group group)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                var access = new GroupAccess();
                var groupDe = access.Single(adc.RootEntry, group.SamAccountName);
                if (groupDe == null)
                {
                    //hack:此处用NullReferenceException这个异常不合适
                    throw new ActiveDirectoryObjectNotFoundException($"组【SamAccountName:{group.SamAccountName}】不存在，更新请求无法继续。");
                }

                //获取管理员员DN
                if (!string.IsNullOrWhiteSpace(group.ManagedBy))
                {
                    var person = new PersonService(ADCInfo).Single(group.ManagedBy);
                    if (person != null)
                        group.ManagedBy = person.DistinguishedName;
                }

                return access.Update(groupDe.GetDirectoryEntry(), group);
            }
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="sAMAccountName">组名称</param>
        /// <returns>成功True，失败False</returns>
        public bool Delete(string sAMAccountName)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                var access = new GroupAccess();
                var groupDe = access.Single(adc.RootEntry, sAMAccountName);
                if (groupDe == null)
                {
                    //hack:此处用NullReferenceException这个异常不合适
                    throw new ActiveDirectoryObjectNotFoundException($"组【sAMAccountName:{sAMAccountName}】不存在，删除请求无法继续。");
                }

                return access.Delete(groupDe.GetDirectoryEntry());
            }
        }

        /// <summary>
        /// 移动
        /// </summary>
        /// <param name="orgCn">移动的目标组织CN</param>
        /// <param name="sAMAccountName">需要移动的组名称</param>
        /// <returns>成功True，失败False</returns>
        public bool Move(string orgCn, string sAMAccountName)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                DirectoryEntry org = null;
                var orgDe = new OrganizationAccess().Single(adc.RootEntry, orgCn);
                if (orgDe == null)
                {
                    //hack:此处用NullReferenceException这个异常不合适
                    throw new ActiveDirectoryObjectNotFoundException($"组织【CN:{orgCn}】不存在，移动组请求无法继续。");
                }
                org = orgDe?.GetDirectoryEntry();

                var access = new GroupAccess();
                var groupDe = access.Single(adc.RootEntry, sAMAccountName);
                if (groupDe == null)
                {
                    //hack:此处用NullReferenceException这个异常不合适
                    throw new ActiveDirectoryObjectNotFoundException($"组【sAMAccountName:{sAMAccountName}】不存在，移动请求无法继续。");
                }
                return access.Move(org, groupDe.GetDirectoryEntry());
            }
        }


        /// <summary>
        /// 搜索组成员(组或人员)
        /// </summary>
        /// <returns></returns>
        public List<DirectoryObject> SearchMembers(string displayName, string orgDN, ConfigItem groupConfig, ConfigItem personConfig)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                OrganizationAccess orgAccess = new OrganizationAccess();
                DirectoryEntry directoryEntry = adc.RootEntry;
                SearchResultCollection src = null;
                //SearchScope searchScope = string.IsNullOrEmpty(orgDN) ? SearchScope.Subtree : SearchScope.OneLevel;

                SearchResult sr = orgAccess.SingleByDistinguishedName(directoryEntry, orgDN);
                if (sr == null)
                {
                    throw new ActiveDirectoryObjectNotFoundException($"组织DN【{orgDN}】不存在，无法继续查询！");
                }
                directoryEntry = sr.GetDirectoryEntry();

                SearchScope searchScope = SearchScope.OneLevel;
                string groupDN = $"OU={groupConfig.name},{orgDN}";
                string personDN = $"OU={personConfig.name},{orgDN}";
                DirectoryEntry groupDe = new DirectoryEntry();
                //查询组
                sr = orgAccess.SingleByDistinguishedName(directoryEntry, groupDN);
                if (sr == null)
                {
                    Organization organization = new Organization()
                    {
                        CN = groupConfig.cn,
                        Name = groupConfig.name,
                        DisplayName = groupConfig.name,
                        Ou = groupConfig.name

                    };
                    orgAccess.Create(directoryEntry, organization);
                    sr = orgAccess.SingleByDistinguishedName(directoryEntry, groupDN);
                }

                groupDe = sr.GetDirectoryEntry();

                //查询用户
                DirectoryEntry personDe = new DirectoryEntry();
                sr = orgAccess.SingleByDistinguishedName(directoryEntry, personDN);
                if (sr == null)
                {
                    Organization organization = new Organization()
                    {
                        CN = personConfig.cn,
                        Name = personConfig.name,
                        DisplayName = personConfig.name,
                        Ou = personConfig.name

                    };

                    orgAccess.Create(directoryEntry, organization);
                    sr = orgAccess.SingleByDistinguishedName(directoryEntry, personDN);
                }

                personDe = sr.GetDirectoryEntry();
                List<DirectoryObject> directoryObjects = new List<DirectoryObject>();
                List<DirectoryObject> groups = new List<DirectoryObject>();
                List<DirectoryObject> persons = new List<DirectoryObject>();

                string filter = "(&(|(objectclass=Group)(objectclass=user)))";

                if (!string.IsNullOrEmpty(displayName))
                {
                    filter = string.Format("(&(|(objectclass=Group)(objectclass=user))(|(displayName=*{0}*)(samAccountName=*{0}*)))", displayName);
                }

                DirectorySearcher dsearcher = new DirectorySearcher(groupDe, filter, null, searchScope);
                src = dsearcher.FindAll();
                //组
                groups = src.OfType<SearchResult>().Select(n =>
             {
                 return (DirectoryObject)n.Properties?.ConvertTo<Group>();

             }).ToList();
                dsearcher = new DirectorySearcher(personDe, filter, null, searchScope);
                src = dsearcher.FindAll();
                //组
                persons = src.OfType<SearchResult>().Select(n =>
              {
                  return (DirectoryObject)n.Properties?.ConvertTo<Person>();

              }).ToList();
                dsearcher = new DirectorySearcher(directoryEntry, filter, null, searchScope);

                directoryObjects.AddRange(groups);
                directoryObjects.AddRange(persons);
                return directoryObjects;

            }
        }


        public List<DirectoryObject> SearchMembersByCondition(string account, string mail, string department, List<Plat_DataPermission> dataPermissions, List<string> systemOus)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                OrganizationAccess orgAccess = new OrganizationAccess();
                DirectoryEntry directoryEntry = adc.RootEntry;
                SearchResultCollection src = null;
                //SearchScope searchScope = string.IsNullOrEmpty(orgDN) ? SearchScope.Subtree : SearchScope.OneLevel;
                StringBuilder sb = new StringBuilder();
                //string filter = "(&(|((objectCategory=Group)(objectClass=Group))((objectCategory=person)(objectClass=user)))";
                sb.Append("(&(|(&(objectCategory=Group)(objectClass=Group))(&(objectCategory=person)(objectClass=person)))");
                if (account != null)
                {
                    sb.AppendFormat("(|(displayName={0}*)(samAccountName={0}*)(cn={0}*))", account);
                }
                if (mail != null)
                {
                    sb.AppendFormat("(mail=*{0}*)", mail);
                }
                if (department != null)
                {
                    sb.AppendFormat("(department=*{0}*)", department);
                }
                sb.Append(")");

                List<DirectoryObject> directoryObjects = new List<DirectoryObject>();

                DirectorySearcher dsearcher = new DirectorySearcher(adc.RootEntry, sb.ToString(), null, SearchScope.Subtree);
                src = dsearcher.FindAll();
                var searchResults = src.OfType<SearchResult>();
                if (base.filterObjectByDataPermission != null)
                {
                    searchResults = filterObjectByDataPermission(searchResults, dataPermissions, systemOus);
                }

                var members = searchResults
                  .Select(n =>
                  {
                      if (n.Properties["objectCategory"][0].ToString().Contains("Group"))
                          return (DirectoryObject)n.Properties?.ConvertTo<Group>();
                      else return (DirectoryObject)n.Properties?.ConvertTo<Person>();
                  }).Distinct(new DirectoryObjectComparerr()).ToList();

                //var copy = members.Select(n => n);
                //members = members.Where(n => !copy.Any(d => d.DistinguishedName == n.DistinguishedName)).ToList();
                return members;

            }
        }
        /// <summary>
        /// 搜索组成员(组或人员)
        /// </summary>
        /// <returns></returns>
        public PageResult<DirectoryObject> MembersPageList(string groupDN, string displayName, Pagination pagination)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                GroupAccess groupAccess = new GroupAccess();
                var groupSr = groupAccess.SingleByDistinguishedName(adc.RootEntry, groupDN);
                var group = groupSr.Properties?.ConvertTo<Group>();
                if (group.Member == null)
                {
                    return PageResult<DirectoryObject>.Default();
                }
                string filter = $"(|{string.Join("", group.Member.Select(item => $"(distinguishedName={item})"))})";

                if (!string.IsNullOrEmpty(displayName))
                {
                    filter = string.Format("(&{0}(|(displayName=*{1}*)(samaccountname=*{1}*)))", filter, displayName);
                }

                DirectorySearcher dsearcher = new DirectorySearcher(adc.RootEntry, filter, null, SearchScope.Subtree);
                var src = dsearcher.FindAll();

                int startNum = Math.Max(pagination.pageNum - 1, 0) * pagination.pageSize;
                var members = src.OfType<SearchResult>().Skip(startNum).Take(pagination.pageSize)
                    .Select(n =>
                    {
                        if (n.Properties["objectCategory"][0].ToString().Contains("Group"))
                            return (DirectoryObject)n.Properties?.ConvertTo<Group>();
                        else return (DirectoryObject)n.Properties?.ConvertTo<Person>();
                    }).ToList();

                pagination.dataCount = src.Count;

                PageResult<DirectoryObject> pageResult = new PageResult<DirectoryObject>(members, pagination);
                return pageResult;

            }

        }

        /// <summary>
        /// 添加组成员
        /// </summary>
        /// <param name="sAMAccountName">需要添加成员的组名称</param>
        /// <param name="members">需要添加的成员</param>
        /// <returns>成功True，失败False</returns>
        public bool AddMember(string dn, List<string> members)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                var access = new GroupAccess();
                var group = access.SingleByDistinguishedName(adc.RootEntry, dn);
                if (group == null)
                {
                    //hack:此处用NullReferenceException这个异常不合适
                    throw new ActiveDirectoryObjectNotFoundException($"组【DB:{dn}】不存在，无法添加成员。");
                }

                return AddMember(group.GetDirectoryEntry(), members, access);
            }
        }

        private bool AddMember(DirectoryEntry groupDe, List<string> members, GroupAccess access)
        {
            //if (groupDe == null || members == null)
            //    return false;
            ////获取人员DN
            //DirectoryObject directoryObject = new DirectoryObject();
            //using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            //{
            //    string filter = $"(|{string.Join("", members.Select(item => $"(distinguishedName={item})"))})";
            //    DirectorySearcher dsearcher = new DirectorySearcher(adc.RootEntry, filter, null, SearchScope.Subtree);
            //    SearchResultCollection result = dsearcher.FindAll();
            //    List<Person> data = new List<Person>();
            //    if (persons == null || persons.Count == 0)
            //    {
            //        return data;
            //    }

            //    foreach (SearchResult item in result)
            //    {
            //        var item = person?.Properties?.ConvertTo<Person>();
            //        if (item != null)
            //        {
            //            data.Add(item);
            //        }
            //    }
            //    return data;
            //}
            //List<string> propertiesToLoad = new List<string> { "distinguishedName", "samaccountname" };

            //var persons = new PersonService(ADCInfo).List(members, propertiesToLoad);
            //if (persons == null || !persons.Any())
            //    return false;

            return access.AddMember(groupDe, members?.Select(d => d).ToList());
        }

        /// <summary>
        /// 删除组成员
        /// </summary>
        /// <param name="sAMAccountName">需要删除成员的组名称</param>
        /// <param name="members">需要删除的成员</param>
        /// <returns>成功True，失败False</returns>
        public bool RemoveMember(string dn, List<string> members)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                var access = new GroupAccess();
                var group = access.SingleByDistinguishedName(adc.RootEntry, dn);
                if (group == null)
                {
                    throw new ActiveDirectoryObjectNotFoundException($"组【DN:{dn}】不存在，无法移除成员。");
                }
                //获取人员DN
                var groupDe = group.GetDirectoryEntry();
                return access.RemoveMember(groupDe, members?.Select(d => d).ToList());
            }
        }

        /// <summary>
        /// 清空组成员
        /// </summary>
        /// <param name="sAMAccountName">组名称</param>
        /// <returns>成功True，失败False</returns>
        public bool ClearMember(string sAMAccountName)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                var access = new GroupAccess();
                var group = access.Single(adc.RootEntry, sAMAccountName);
                if (group == null)
                {
                    throw new ActiveDirectoryObjectNotFoundException($"组【sAMAccountName:{sAMAccountName}】不存在，无法清空成员。");
                }

                var groupDe = group.GetDirectoryEntry();
                return access.ClearMember(groupDe);
            }
        }
    }
}
